package com.bidepan.reflect;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestCar {
    //1. 获取Class对象（字节码对象）多种方式
    @Test
    public void test1() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1)类名.class;
        Class<Car>clazz1 = Car.class;
        //2) 对象的getClass()方法
        Class<Car> clazz2 = (Class<Car>) new Car().getClass();
        //3) Class.forName()方法
        Class<Car> clazz3 = (Class<Car>) Class.forName("com.bidepan.reflect.Car");
        System.out.println(clazz1);
        System.out.println(clazz2);
        System.out.println(clazz3);
        //实例化
        Car car = clazz1.getDeclaredConstructor().newInstance();
        System.out.println(car);
    }

    //2.获取构造方法
    @Test
    public void test2() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<Car> clazz = Car.class;
        //获取所有构造（不带Declared则只能获取public方法）
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor c : constructors) {
            System.out.println("构造方法名称："+c.getName()+" 参数个数："+c.getParameterCount());
        }
        //指定用有参构造创建对象
        //1.构造为public
        Constructor c1 = clazz.getConstructor(String.class,int.class,String.class);
        Car car1 = (Car)c1.newInstance("法拉利",6,"落日黄");
        System.out.println(car1);
        //2.构造为private
        Constructor c2 = clazz.getDeclaredConstructor(String.class,String.class);
        c2.setAccessible(true);     //必须加上
        Car car2 = (Car)c2.newInstance("红旗","烈焰红");
        System.out.println(car2);
    }


    //3.获取属性
    @Test
    public void test3() throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<Car> clazz = Car.class;
        //获取所有public属性
        Field[] fields = clazz.getFields();
        System.out.println("所有public属性：");
        for (Field f : fields) {
            System.out.println("属性名称："+f.getName());
        }
        System.out.println("所有属性：(包括private)：");
        //获取所有属性（包含private属性）
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field f : declaredFields) {
            System.out.println("属性名称："+f.getName());
        }
        //得到属性后进行修改
        //先实例化一个对象
        Car car = (Car)clazz.getDeclaredConstructor().newInstance();
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);     //设置private属性允许被调用
        nameField.set(car,"布加迪");
        System.out.println(car);
    }

    //4.获取方法
    @Test
    public void Test4() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Car car =  new Car("小米su7",1,"蓝色");
        Class clazz = car.getClass();
        //1.public方法
        Method[] methods = clazz.getMethods();
        for(Method method : methods){
            //System.out.println("方法名称："+method.getName());
            //执行指定方法 toString
            if(method.getName().equals("toString")){
                String invoke = (String) method.invoke(car);
                System.out.println("toString方法执行了：返回值为"+invoke);
            }

        }
        //2.private方法
        Method privateMethod = clazz.getDeclaredMethod("run");
        privateMethod.setAccessible(true);     //设置private方法允许被调用
        privateMethod.invoke(car);
    }
}
